﻿using AutoMapper;
using Hotel.Application.Admins.Dto;
using Hotel.Domain;
using Hotel.Repositories;
using Hotel.Utility;
using IdentityModel;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Hotel.Application.Admins
{
    public class AdminService : BaseService<Admin, AdminCreateUpdateDto, AdminListDto>, IAdminService
    {
        private readonly IRepository<Admin> repository;
        private readonly IHttpContextAccessor httpContext;
        private readonly ICaptcha captcha;
        private readonly IRepository<Role> roleRepository;

        public AdminService(
            IRepository<Admin> repository, 
            IMapper mapper,
            IHttpContextAccessor httpContext,
            ICaptcha captcha,
            IRepository<Role> RoleRepository
            ) : base(repository)
        {
            this.repository = repository;
            this.mapper = mapper;
            this.httpContext = httpContext;
            this.captcha = captcha;
            roleRepository = RoleRepository;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public async Task<ResultDto> LoginAsync(LoginDto dto)
        {
            var context = httpContext.HttpContext;
            if (!captcha.Validate(context.Request.Cookies["ValidateCode"], dto.ValidateCode))
            {
                return new ResultLoginDto { code = State.Failed, msg = "验证码不正确" };
            }
            var admin = await repository.FirstAsync(m => m.UserName == dto.UserName);
            if (admin == null)
            {
                return new ResultLoginDto { code = State.Failed, msg = "无此用户" };
            }
            else
            {
                if (admin.Password == MD5Helper.MD5Hash(dto.Password))
                {
                    //更新末次登录IP和末次登录时间
                    admin.LastLoginIP = httpContext.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
                    admin.LastLoginTime = DateTime.Now;
                    await repository.UpdateAsyc(admin);

                    //身份信息认证
                    //写Session或Cookies换成JWT
                    IList<Claim> claims = new List<Claim> {
                        new Claim(JwtClaimTypes.Id,admin.AdminId.ToString()),
                        new Claim(JwtClaimTypes.Name,admin.UserName),
                        new Claim(ClaimTypes.Name,admin.UserName),
                        new Claim(ClaimTypes.NameIdentifier,admin.UserName)
                    };
                    var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                    var authProperties = new Microsoft.AspNetCore.Authentication.AuthenticationProperties
                    {
                        AllowRefresh = true,
                        IsPersistent = true,
                        ExpiresUtc = DateTime.Now.AddDays(5),
                        RedirectUri = "/Home/Captcha",
                        IssuedUtc = DateTime.Now.AddDays(5)
                    };
                    //authProperties.Parameters.Add("abc", "123");

                    await context.SignInAsync
                    (
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    new ClaimsPrincipal(claimsIdentity),
                    authProperties
                    );
                    return new ResultDto { code = State.Success };
                }
                else
                {
                    return new ResultLoginDto { code = State.Failed, msg = "密码错误" };
                }
            }
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public override async Task<long> InsertAsync(AdminCreateUpdateDto dto)
        {
            dto.Password = MD5Helper.MD5Hash(dto.Password);
            return await base.InsertAsync(dto);
        }

        public override ResultDto<List<AdminListDto>> ToPageList(int PageSize = 10, int PageIndex = 1)
        {
            return base.ToPageList(PageSize, PageIndex);
        }

        public async Task<ResultDto<bool>> CheckName(string UserName,long AdminId)
        {
            return new ResultDto<bool> {
                code = State.Success, 
                data = await repository.AnyAsync(m => m.UserName == UserName && m.AdminId != AdminId)
            };
        }

        public override Task<int> UpdateAsyc(AdminCreateUpdateDto dto)
        {
            Admin admin = mapper.Map<Admin>(dto);
            if (!string.IsNullOrEmpty(dto.Password))
            {
                admin.Password = MD5Helper.MD5Hash(admin.Password);
                return repository.UpdateAsyc(admin);
            }
            else
            {
                return repository.UpdateByFieldsAsyc(admin, nameof(Admin.UserName),nameof(Admin.Email));
            }
        }
    }
}
